package com.wedistudio.android.framework.pool;

import java.util.HashMap;
import java.util.Map;

import nf.fr.eraasoft.pool.ObjectPool;
import nf.fr.eraasoft.pool.PoolException;
import nf.fr.eraasoft.pool.PoolSettings;
import nf.fr.eraasoft.pool.PoolableObjectBase;

import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;

import android.util.Log;

public class PoolFactory {

	private static Map<Class<?>, ObjectPool<?>> OBJECT_POOL_MAP;
	
	//basic initialization
	static {
		
		OBJECT_POOL_MAP = new HashMap<Class<?>, ObjectPool<?>>(
				10);
		
		register(Serializer.class,
				new PoolMakeStrategy<Serializer>() {

					@Override
					public Serializer make() {
						return new Persister();
					}
				}, new PoolActivateStrategy<Serializer>() {

					@Override
					public void activate(Serializer t) {
					}
				}, 0, 10);
		
		
		register(StringBuilder.class,
				new PoolMakeStrategy<StringBuilder>() {

					@Override
					public StringBuilder make() {
						return new StringBuilder();
					}
				}, new PoolActivateStrategy<StringBuilder>() {

					@Override
					public void activate(StringBuilder t) {
						t.setLength(0);
					}
				}, 0, 10);
	}
	
	

	public static <T> void register(Class<T> cl,
			final PoolMakeStrategy<T> make,
			final PoolActivateStrategy<T> activate, int min, int max) {
		if (OBJECT_POOL_MAP.containsValue(cl))
			throw new RuntimeException(cl + " pool already defined");

		PoolSettings<T> poolSettings = new PoolSettings<T>(
				new PoolableObjectBase<T>() {
					@Override
					public T make() {
						return make.make();
					}

					@Override
					public void activate(T t) {
						activate.activate(t);
					}
				});
		// Add some settings
		poolSettings.min(min).max(max);

		Log.d("PoolFactory", "register " + cl);
		OBJECT_POOL_MAP.put(cl, poolSettings.pool());
	}

	@SuppressWarnings("unchecked")
	public static <T> ObjectPool<T> pool(Class<T> cl) {
		ObjectPool<T> pool = (ObjectPool<T>) OBJECT_POOL_MAP.get(cl);
		if (pool == null)
			throw new RuntimeException(cl + " pool is not defined");

		return pool;
	}

	public static <T> T get(Class<T> cl) {
		ObjectPool<T> pool = pool(cl);
		try {
			return pool.getObj();
		} catch (PoolException e) {
			throw new RuntimeException(e);
		}
	}

	@SuppressWarnings("unchecked")
	public static <T> void release(Object o) {
		if (o == null)
			return;

		ObjectPool<T> pool = (ObjectPool<T>) pool(o.getClass());
		pool.returnObj((T) o);
	}

	@SuppressWarnings("unchecked")
	public static <T> void release(Object o, Class<T> cl) {
		if (o == null)
			return;

		ObjectPool<T> pool = (ObjectPool<T>) pool(cl);
		pool.returnObj((T) o);
	}

}
